package com.qzsoft.zhjd.server.socket.handler;

import com.qzsoft.zhjd.server.modules.cement.model.CementCollectDataModel;
import com.qzsoft.zhjd.server.modules.cement.service.CollectCementDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;

import com.qzsoft.zhjd.server.common.utils.R;
import com.qzsoft.zhjd.server.modules.asphalt.model.CollectDataModel;
import com.qzsoft.zhjd.server.modules.asphalt.service.CollectAsphaltReceiveService;
import com.qzsoft.zhjd.server.socket.config.TcpReceiveConstants;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.socket.SocketChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName TcpReceiveMessageHandler
 * @Description 数据处理
 * @author linhuawei
 * @since 2022-01-12
 */
@Slf4j
@Sharable
@Component
public class TcpReceiveMessageHandler extends SimpleChannelInboundHandler<String> {

    @Autowired
    private CollectAsphaltReceiveService collectAsphaltReceiveService;

    @Autowired
    private CollectCementDataService collectCementDataService;

    private String msgCache = "";

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        SocketChannel socketChannel = (SocketChannel) ctx.channel();

        // 判断是否为空
        if (ObjectUtils.isEmpty(msg)) {
            log.info("接收到的数据为空");
            sendError(socketChannel);
            return;
        }

        // 莱阳DTU心跳数据，后续可以删除
        if ("514c4a544c5130310d0a".equals(msg) || "QLJTLQ01\r\n".equals(msg)) {
            log.info("莱阳心跳数据");
            sendError(socketChannel);
            return;
        }

        // 心跳包，使用dtu传输数据时，传递内容未qzsoft转16进制字符串
        if("717a736f6674".equals(msg) || "qzsoft".equals(msg)) {
            msg = "{\"type\": \"heartbeat\"}";
            log.info("采集设备DTU心跳");
        }

        // 处理粘包、分包问题
        // 缓存数据里面没有开始符，不做后续处理，并且清空缓存数据
        msgCache = msgCache + msg;
        log.info("缓存前数据：\r\n{}\r\n=====\r\n{}", msg, msgCache);
        int start = msgCache.indexOf("{");
        if (-1 == start) {
            msgCache = "";
            return;
        }

        // 找到开始字符进行处理
        while ((start = msgCache.indexOf("{")) != -1) {
            // 获取结束位置
            int end = msgCache.indexOf("}");
            if (-1 == end) {
                break;
            }
            if(end <= start) {
                msgCache = msgCache.substring(start, msgCache.length());
                continue;
            }

            // 截取有效内容
            msg = msgCache.substring(start, end + 1);

            // 判有效内容中是否还有开始字符
            start = msg.lastIndexOf("{");
            if (0 < start) {
                msg = msg.substring(start);
            }

            // 截取有效内容后续数据
            msgCache = msgCache.substring(end + 1);

            // 处理有效数据
            handler(msg, socketChannel);
        }

        // 如果处理完剩余的数据没有开始字符，清空缓存
        start = msgCache.indexOf("{");
        if (-1 == start) {
            msgCache = "";
        }
    }

    /**
     * @Title handler
     * @Description 处理接收到的数据
     * @param msg           数据内容
     * @param socketChannel
     */
    private void handler(String msg, SocketChannel socketChannel) {
        // 数据转化
        JSONObject json = null;
        try {
            json = JSONObject.parseObject(msg);
        } catch (Exception e) {
            log.info("接收到的数据格式化失败：{}", msg);
            sendError(socketChannel);
            return;
        }

        // 获取数据类型
        String type = json.getString("type");
        if (ObjectUtils.isEmpty(type)) {
            log.info("未知的数据类型：{}", msg);
            sendError(socketChannel);
            return;
        }

        if (TcpReceiveConstants.TYPE_HEARTBEAT.equals(type)) {// 心跳数据
            log.info("心跳数据：{}", msg);
            send(socketChannel, R.ok());
            return;
        }

        if (TcpReceiveConstants.TYPE_ASPHALT_DATA.equals(type)) {// 沥青数据
            handlerAsphaltData(msg, socketChannel);
            return;
        }

        if (TcpReceiveConstants.TYPE_CEMENT_DATA.equals(type)) {// 水稳数据
            handlerCementData(msg, socketChannel);
            return;
        }

        log.info("未知的数据类型：{}", msg);
        sendError(socketChannel);
        return;
    }

    /**
     * @Title handlerAsphaltData
     * @Description 处理沥青数据
     * @param msg
     * @param socketChannel
     */
    private void handlerAsphaltData(String msg, SocketChannel socketChannel) {
        log.info("沥青数据：{}", msg);

        // 获取沥青数据
        CollectDataModel model = null;
        try {
            model = JSONObject.parseObject(msg, CollectDataModel.class);
        } catch (Exception e) {
            model = null;
        }

        // 判断数据是否为空
        if (null == model) {
            send(socketChannel, R.error());
        } else {
            try {
                collectAsphaltReceiveService.receive(model);
                send(socketChannel, R.ok(model.getId()));
            } catch (Exception e) {
                log.error("{}", e);
                send(socketChannel, R.error());
            }
        }
    }

    /**
     * @Title handlerAsphaltData
     * @Description 处理水稳数据
     * @param msg
     * @param socketChannel
     */
    private void handlerCementData(String msg, SocketChannel socketChannel) {
        log.info("水稳数据：{}", msg);

        // 获取水稳数据
        CementCollectDataModel model = null;
        try {
            model = JSONObject.parseObject(msg, CementCollectDataModel.class);
        } catch (Exception e) {
            model = null;
        }

        // 判断数据是否为空
        if (null == model) {
            send(socketChannel, R.error());
        } else {
            try {
                collectCementDataService.save(model);
                send(socketChannel, R.ok(model.getId()));
            } catch (Exception e) {
                log.error("{}", e);
                send(socketChannel, R.error());
            }
        }
    }

    /**
     * @Title send
     * @Description 数据处理结果返回
     * @param socketChannel
     * @param resp
     */
    private void send(SocketChannel socketChannel, R resp) {
        try {
            String message = JSONObject.toJSONString(resp);
            socketChannel.writeAndFlush(message).addListener(future -> {
                if (future.isSuccess()) {
                    log.info("数据回复成功：resp = {}", resp);
                } else {
                    log.info("数据回复失败：resp = {}", resp);
                }
            });
        } catch (Exception e) {
            log.info("数据回复异常：resp = {}, ex = {}", resp, e.getMessage());
        }
    }

    /**
     * @Title sendError
     * @Description 返回错误信息
     * @param socketChannel
     */
    private void sendError(SocketChannel socketChannel) {
        String message = "(-3)";
        try {
            socketChannel.writeAndFlush(message).addListener(future -> {
                if (future.isSuccess()) {
                    log.info("数据回复成功：resp = {}", message);
                } else {
                    log.info("数据回复失败：resp = {}", message);
                }
            });
        } catch (Exception e) {
            log.info("数据回复异常：resp = {}, ex = {}", message, e.getMessage());
        }
    }
}
